﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using IPC.Communication.Core;
using IPC.Communication.Core.Net;
using IPC.Communication.Reflection;

namespace IPC.Communication.Profinet.Keyence
{
    public class KeyenceNanoSerialOverTcp : NetworkDeviceBase
    {
        public byte Station
        {
            get;
            set;
        }

        public bool UseStation
        {
            get;
            set;
        }

        public KeyenceNanoSerialOverTcp()
        {
            base.WordLength = 1;
            base.ByteTransform = new RegularByteTransform();
        }

        public KeyenceNanoSerialOverTcp(string ipAddress, int port = 8501)
            : this()
        {
            IpAddress = ipAddress;
            Port = port;
        }

        protected override OperateResult InitializationOnConnect(Socket socket)
        {
            OperateResult<byte[]> operateResult = ReadFromCoreServer(socket, KeyenceNanoHelper.GetConnectCmd(Station, UseStation));
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            return OperateResult.CreateSuccessResult();
        }

        protected override OperateResult ExtraOnDisconnect(Socket socket)
        {
            OperateResult<byte[]> operateResult = ReadFromCoreServer(socket, KeyenceNanoHelper.GetDisConnectCmd(Station, UseStation));
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            return OperateResult.CreateSuccessResult();
        }

        public override OperateResult<byte[]> ReadFromCoreServer(Socket socket, byte[] send, bool hasResponseData = true, bool usePackHeader = true)
        {
            if (base.LogNet != null)
            {
                base.LogNet.WriteDebug(ToString(), StringResources.Language.Send + " : " + (LogMsgFormatBinary ? send.ToHexString(' ') : Encoding.ASCII.GetString(send)));
            }
            OperateResult operateResult = Send(socket, usePackHeader ? PackCommandWithHeader(send) : send);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            if (receiveTimeOut < 0)
            {
                return OperateResult.CreateSuccessResult(new byte[0]);
            }
            if (!hasResponseData)
            {
                return OperateResult.CreateSuccessResult(new byte[0]);
            }
            if (base.SleepTime > 0)
            {
                Thread.Sleep(base.SleepTime);
            }
            OperateResult<byte[]> operateResult2 = ReceiveCommandLineFromSocket(socket, 13, 10, receiveTimeOut);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            if (base.LogNet != null)
            {
                base.LogNet.WriteDebug(ToString(), StringResources.Language.Receive + " : " + (LogMsgFormatBinary ? operateResult2.Content.ToHexString(' ') : Encoding.ASCII.GetString(operateResult2.Content)));
            }
            return OperateResult.CreateSuccessResult(operateResult2.Content);
        }

        //[AsyncStateMachine(typeof(<InitializationOnConnectAsync>d__5))]
        //[DebuggerStepThrough]
        //protected override Task<OperateResult> InitializationOnConnectAsync(Socket socket)
        //{
        //    <InitializationOnConnectAsync>d__5 stateMachine = new <InitializationOnConnectAsync>d__5();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.socket = socket;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ExtraOnDisconnectAsync>d__6))]
        //[DebuggerStepThrough]
        //protected override Task<OperateResult> ExtraOnDisconnectAsync(Socket socket)
        //{
        //    <ExtraOnDisconnectAsync>d__6 stateMachine = new <ExtraOnDisconnectAsync>d__6();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.socket = socket;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadFromCoreServerAsync>d__7))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<byte[]>> ReadFromCoreServerAsync(Socket socket, byte[] send, bool hasResponseData = true, bool usePackHeader = true)
        //{
        //    <ReadFromCoreServerAsync>d__7 stateMachine = new <ReadFromCoreServerAsync>d__7();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.socket = socket;
        //    stateMachine.send = send;
        //    stateMachine.hasResponseData = hasResponseData;
        //    stateMachine.usePackHeader = usePackHeader;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("ReadByteArray", "")]
        public override OperateResult<byte[]> Read(string address, ushort length)
        {
            return KeyenceNanoHelper.Read(this, address, length);
        }

        [HslMqttApi("WriteByteArray", "")]
        public override OperateResult Write(string address, byte[] value)
        {
            return KeyenceNanoHelper.Write(this, address, value);
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__18))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
        //{
        //    <ReadAsync>d__18 stateMachine = new <ReadAsync>d__18();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__19))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, byte[] value)
        //{
        //    <WriteAsync>d__19 stateMachine = new <WriteAsync>d__19();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("ReadBoolArray", "")]
        public override OperateResult<bool[]> ReadBool(string address, ushort length)
        {
            return KeyenceNanoHelper.ReadBool(this, address, length);
        }

        [HslMqttApi("WriteBool", "")]
        public override OperateResult Write(string address, bool value)
        {
            return KeyenceNanoHelper.Write(this, address, value);
        }

        [HslMqttApi("WriteBoolArray", "")]
        public override OperateResult Write(string address, bool[] value)
        {
            return KeyenceNanoHelper.Write(this, address, value);
        }

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__23))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult<bool[]>> ReadBoolAsync(string address, ushort length)
        //{
        //    <ReadBoolAsync>d__23 stateMachine = new <ReadBoolAsync>d__23();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__24))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, bool value)
        //{
        //    <WriteAsync>d__24 stateMachine = new <WriteAsync>d__24();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteAsync>d__25))]
        //[DebuggerStepThrough]
        //public override Task<OperateResult> WriteAsync(string address, bool[] value)
        //{
        //    <WriteAsync>d__25 stateMachine = new <WriteAsync>d__25();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        [HslMqttApi("查询PLC的型号信息")]
        public OperateResult<KeyencePLCS> ReadPlcType()
        {
            return KeyenceNanoHelper.ReadPlcType(this);
        }

        [HslMqttApi("读取当前PLC的模式，如果是0，代表 PROG模式或者梯形图未登录，如果为1，代表RUN模式")]
        public OperateResult<int> ReadPlcMode()
        {
            return KeyenceNanoHelper.ReadPlcMode(this);
        }

        [HslMqttApi("设置PLC的时间")]
        public OperateResult SetPlcDateTime(DateTime dateTime)
        {
            return KeyenceNanoHelper.SetPlcDateTime(this, dateTime);
        }

        [HslMqttApi("读取指定软元件的注释信息")]
        public OperateResult<string> ReadAddressAnnotation(string address)
        {
            return KeyenceNanoHelper.ReadAddressAnnotation(this, address);
        }

        [HslMqttApi("从扩展单元缓冲存储器连续读取指定个数的数据，单位为字")]
        public OperateResult<byte[]> ReadExpansionMemory(byte unit, ushort address, ushort length)
        {
            return KeyenceNanoHelper.ReadExpansionMemory(this, unit, address, length);
        }

        [HslMqttApi("将原始字节数据写入到扩展的缓冲存储器，需要指定单元编号，偏移地址，写入的数据")]
        public OperateResult WriteExpansionMemory(byte unit, ushort address, byte[] value)
        {
            return KeyenceNanoHelper.WriteExpansionMemory(this, unit, address, value);
        }

        //[AsyncStateMachine(typeof(<ReadPlcTypeAsync>d__32))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<KeyencePLCS>> ReadPlcTypeAsync()
        //{
        //    <ReadPlcTypeAsync>d__32 stateMachine = new <ReadPlcTypeAsync>d__32();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<KeyencePLCS>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadPlcModeAsync>d__33))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<int>> ReadPlcModeAsync()
        //{
        //    <ReadPlcModeAsync>d__33 stateMachine = new <ReadPlcModeAsync>d__33();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<int>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<SetPlcDateTimeAsync>d__34))]
        //[DebuggerStepThrough]
        //public Task<OperateResult> SetPlcDateTimeAsync(DateTime dateTime)
        //{
        //    <SetPlcDateTimeAsync>d__34 stateMachine = new <SetPlcDateTimeAsync>d__34();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.dateTime = dateTime;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadAddressAnnotationAsync>d__35))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<string>> ReadAddressAnnotationAsync(string address)
        //{
        //    <ReadAddressAnnotationAsync>d__35 stateMachine = new <ReadAddressAnnotationAsync>d__35();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<string>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.address = address;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<ReadExpansionMemoryAsync>d__36))]
        //[DebuggerStepThrough]
        //public Task<OperateResult<byte[]>> ReadExpansionMemoryAsync(byte unit, ushort address, ushort length)
        //{
        //    <ReadExpansionMemoryAsync>d__36 stateMachine = new <ReadExpansionMemoryAsync>d__36();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.unit = unit;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        //[AsyncStateMachine(typeof(<WriteExpansionMemoryAsync>d__37))]
        //[DebuggerStepThrough]
        //public Task<OperateResult> WriteExpansionMemoryAsync(byte unit, ushort address, byte[] value)
        //{
        //    <WriteExpansionMemoryAsync>d__37 stateMachine = new <WriteExpansionMemoryAsync>d__37();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.<>4__this = this;
        //    stateMachine.unit = unit;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public override string ToString()
        {
            return String.Format("KeyenceNanoSerialOverTcp[{0}:{1}]", IpAddress, Port);
        }
    }
}